#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'进程、多线程练习'

__author__ = '许文杰'

import os, time, random, threading
from multiprocessing import Process, Queue
from multiprocessing import Pool
import subprocess

# 线程，python提供了两个模块，_thread是低级模块，threading是高级模块，对_thread进行了封装。绝大多数情况下，我们只需要使用threading这个高级模块
# 多线程和多进程最大的不同在于，多进程中，同一个变量，各自有一份拷贝存在于每个进程中，互不影响，
# 而多线程中，所有变量都由所有线程共享，所以，任何一个变量都可以被任何一个线程修改，
# 因此，线程之间共享数据最大的危险在于多个线程同时改一个变量，把内容给改乱了。所以，就有了线程锁
def func1():
    print('process %s start ' % os.getpid())

    pid = os.fork()

    if pid == 0:
        print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
    else:
        print('I (%s) just created a child process (%s).' % (os.getpid(), pid))

# func1()

def func2(name):
    print('Run child process %s (%s)...' % (name, os.getpid()))

def long_time_task(name):
    print('run task %s (%s)' %(name, os.getpid()))
    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print('task %s runs %.2f second' % (name, (end - start)))


def write(q):
    print('Print to write %s ' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('put %s to queue' % value)
        q.put(value)
        time.sleep(random.random())

def read(q):
    print('Process to read: %s' % os.getpid())
    while True:
        value = q.get(True)
        print('Get %s from queue.' % value)



# 新线程执行的代码:
def loop():
    print('thread %s is running...' % threading.current_thread().name)
    n = 0
    while n < 5:
        n += 1
        print('thread %s >>> %s' % (threading.current_thread().name, n))
        time.sleep(1)
    print('thread %s ended.' % threading.current_thread().name)

# 假定这是你的银行存款:
balance = 0
lock = threading.Lock()

def change_it(n):
    # 先存后取，结果应该为0:
    global balance
    balance = balance + n
    balance = balance - n

def run_thread(n):
    for i in range(100000):
        # 先获取锁
        lock.acquire()
        try:
            # 可以放心的修改，在该线程没有执行完毕前，其他线程不能做修改
            change_it(n)
        finally:
            # 使用完要释放
            lock.release()

# 创建全局ThreadLocal对象:
local_school = threading.local()

def process_student():
    # 获取当前线程关联的student:
    std = local_school.student
    print('Hello, %s (in %s)' % (std, threading.current_thread().name))

def process_thread(name):
    local_school.student = name
    process_student()

if __name__ == '__main__':

    # print('parent process %s' % os.getpid())
    # p = Process(target=func2, args=('test', ))
    # print('child process will start')
    # p.start()
    # p.join()
    # print('child process end')

    # 进程池
    # print('parent process %s' % os.getpid())
    # p = Pool(4)
    # for i in range(5):
    #     p.apply_async(long_time_task, args=(i, ))
    # p.close()
    # p.join()
    # print('all processes done')

    # print('$ nslookup www.python.org')
    # r = subprocess.call(['nslookup', 'www.baidu.com'])
    # print('Exit code ', r)

    # q = Queue()
    # pw = Process(target=write, args=(q, ))
    # pr = Process(target=read, args=(q, ))

    # 启动子进程pw，写入
    # pw.start()
    # 启动子进程pr，读取
    # pr.start()
    # 等待pw结束:
    # pw.join()
    # pr进程里是死循环，无法等待其结束，只能强行终止:
    # pr.terminate()

    # pass
    # print('thread %s is running...' % threading.current_thread().name)
    # t = threading.Thread(target=loop, name='LoopThread')
    # t.start()
    # t.join()
    # print('thread %s ended.' % threading.current_thread().name)

    # t1 = threading.Thread(target=run_thread, args=(5, ))
    # t2 = threading.Thread(target=run_thread, args=(8, ))
    # t1.start()
    # t2.start()
    # t1.join()
    # t2.join()
    # print(balance)

    t1 = threading.Thread(target=process_thread, args=('aaa', ), name='thread-A')
    t2 = threading.Thread(target=process_thread, args=('bbb', ), name='thread-B')
    t1.start()
    t2.start()
    t1.join()
    t2.join()